package com.kun.admin.authority.service;

import com.kun.admin.authority.dao.MenuDao;
import com.kun.admin.authority.model.MenuItem;
import com.xiaoleilu.hutool.collection.CollUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Created by likun on 2017/1/17.
 */
@Service
public class AuthorityMenuServiceImpl implements AuthorityMenuService {

    @Autowired
    private MenuDao menuDao;

    @Override
    public MenuItem findMenuItem() {
        ArrayList<MenuItem> items=menuDao.findAll();
        MenuItem menu=new MenuItem();
        menu.setName("菜单列表");
        menu.setLvl(-1);
        ArrayList<MenuItem> menuList=new ArrayList<>();
        menu.setChildren(menuList);
        genMenu(items,menuList); //组装树状结构数据
        return menu;
    }

    /**
     * 获取所有的菜单列表
     * @return
     */
    @Override
    public ArrayList<MenuItem> finMenuItemAll() {
        MenuItem menuItem = findMenuItem();
        ArrayList<MenuItem> menuList=new ArrayList<>();
        menu2list(menuItem.getChildren(),menuList);
        return menuList;
    }

    /**
     * 将递归树形菜单读取成list
     * @param children
     * @param menuList
     */
    private void menu2list(ArrayList<MenuItem> children, ArrayList<MenuItem> menuList) {
        if (children!=null && children.size()>0){
            for (MenuItem item:children){
                menuList.add(item);
                if (item.getChildren()!=null && item.getChildren().size()>0){
                    menu2list(item.getChildren(),menuList);
                }
            }
        }
    }

    /**
     * 根据id获取资源
     * @param menuId  菜单id
     * @return
     */
    @Override
    public MenuItem findMenuById(Long menuId) {
        List<MenuItem> menuItemList=menuDao.findMenuById(menuId);
        if (menuItemList==null || menuItemList.size()==0){
            return null;
        }
        return menuItemList.get(0);
    }

    /**
     * 更新菜单资源
     * @param menu
     * @return
     */
    @Override
    public boolean update(MenuItem menu) {
        int i=menuDao.update(menu);
        return i > 0;
    }

    /**
     * 添加菜单
     * @param menu
     * @return
     */
    @Override
    public boolean create(MenuItem menu) {
        //设置菜单等级
        if (menu.getPrentId()!=null){
            List<MenuItem> prentMenu = menuDao.findMenuById(menu.getPrentId());
            if (prentMenu!=null && prentMenu.size()>0){
                MenuItem pm = prentMenu.get(0);
                if (pm.getLvl()==null || pm.getLvl().intValue()==0){
                    menu.setLvl(1);
                }else {
                    menu.setLvl(pm.getLvl()+1);
                }
            }else {
                return false;
            }
        }
        long id=menuDao.create(menu);
        return id > 0;
    }

    /**
     * 删除菜单
     * @param id
     * @return
     */
    @Override
    public boolean delete(Long id) {
        MenuItem menuItem = findMenuItem();
        List<Long> ids = new ArrayList<>();
        if (CollUtil.isNotEmpty(menuItem.getChildren())) {
            menuItem.getChildren().forEach(item -> eachMenu(item, ids, id, true));
        }
        int row = 0;
        for (Long i : ids) {
            row += menuDao.delete(i);
        }
        return row > 0;
    }

    @Override
    public MenuItem findUserMenuItem(Long userId) {
        ArrayList<MenuItem> items=menuDao.findUserMenu(userId);
        MenuItem menu=new MenuItem();
        menu.setName("菜单列表");
        menu.setLvl(-1);
        menu.setType(0);
        ArrayList<MenuItem> menuList=new ArrayList<>();
        menu.setChildren(menuList);
        if (items.size()>0){
            //组装树状结构数据
            genMenu(items,menuList);
        }
        return menu;
    }

    private void eachMenu(MenuItem item, List<Long> ids, Long id, boolean equalsId) {
        if (equalsId) {
            if (item.getId() != null && id.equals(item.getId())) {
                ids.add(item.getId());
                if (CollUtil.isNotEmpty(item.getChildren())) {
                    item.getChildren().forEach(i -> eachMenu(i, ids, id, false));
                }
            } else {
                if (CollUtil.isNotEmpty(item.getChildren())) {
                    item.getChildren().forEach(i -> eachMenu(i, ids, id, true));
                }
            }
        } else {
            ids.add(item.getId());
            if (CollUtil.isNotEmpty(item.getChildren())) {
                item.getChildren().forEach(i -> eachMenu(i, ids, id, equalsId));
            }
        }

    }


    /**
     * 组装树状结构数据
     * @param items
     * @param menuList
     */
    private void genMenu(ArrayList<MenuItem> items, ArrayList<MenuItem> menuList){
        int maxLvl=selectMaxLvl(items);
        Iterator<MenuItem> it = items.iterator();
        while (it.hasNext()) {
            MenuItem item=it.next();
            if (item.getPrentId()==null||item.getPrentId()==-1){
                menuList.add(item);
            }
        }
        for (MenuItem item:menuList){
            selectChildren(item,items,maxLvl,1);
        }
    }

    /**
     * 递归组装
     * @param item
     * @param items
     * @param maxLvl
     * @param lvl
     */
    private void selectChildren(MenuItem item, ArrayList<MenuItem> items, int maxLvl, int lvl) {
        if (lvl<=maxLvl){
            if (item.getChildren()==null){
                item.setChildren(new ArrayList<>());
            }
            for (MenuItem it:items){
                if (item.getId().equals(it.getPrentId())){
                    item.getChildren().add(it);
                }
            }
            lvl++;
            for (MenuItem it:item.getChildren()){
                selectChildren(it,items,maxLvl,lvl);
            }
        }
    }

    /**
     * 获取树状结构最大的等级
     * @param items
     * @return
     */
    private int selectMaxLvl(ArrayList<MenuItem> items) {
        int lvl=-2;
        for (MenuItem item:items) {
            if (item.getLvl()!=null && item.getLvl()>lvl){
                lvl=item.getLvl();
            }
        }
        return lvl;
    }


}
